package xx.iverson.file_manager.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import xx.iverson.file_manager.entity.FileInfo;
import xx.iverson.file_manager.service.FileInfoService;
import xx.iverson.file_manager.util.FileUploadUtil;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

/**
 * xx.iverson.file_manager.controller.FileUploadController
 * 描述：
 * on 2025/9/22-上午11:16
 *
 * @author weijx
 */


@RestController
@RequestMapping("/api/file")
public class FileUploadController {

    @Autowired
    private FileUploadUtil fileUploadUtil;

    @Autowired
    private FileInfoService fileInfoService;

    /**
     * 检查分片是否存在（用于断点续传）
     */
    @GetMapping("/chunk")
    public ResponseEntity<Map<String, Object>> checkChunk(
            @RequestParam String fileMd5,
            @RequestParam Integer chunkIndex) {

        Map<String, Object> result = new HashMap<>();
        boolean exists = fileUploadUtil.checkChunk(fileMd5, chunkIndex);
        result.put("exists", exists);

        return ResponseEntity.ok(result);
    }

    /**
     * 获取已上传的分片列表
     */
    @GetMapping("/chunks")
    public ResponseEntity<Map<String, Object>> getUploadedChunks(
            @RequestParam String fileMd5) {

        Map<String, Object> result = new HashMap<>();
        Integer[] uploadedChunks = fileUploadUtil.getUploadedChunks(fileMd5);
        result.put("uploadedChunks", uploadedChunks);

        return ResponseEntity.ok(result);
    }

    /**
     * 上传文件分片
     */
    @PostMapping("/upload/chunk")
    public ResponseEntity<Map<String, Object>> uploadChunk(
            @RequestParam("file") MultipartFile file,
            @RequestParam String fileMd5,
            @RequestParam Integer chunkIndex,
            @RequestParam Integer totalChunks) {

        Map<String, Object> result = new HashMap<>();

        try {
            boolean success = fileUploadUtil.processChunk(file, fileMd5, chunkIndex, totalChunks);
            result.put("success", success);
            result.put("message", "分片上传成功");
        } catch (IOException e) {
            result.put("success", false);
            result.put("message", "分片上传失败: " + e.getMessage());
        }

        return ResponseEntity.ok(result);
    }

    /**
     * 合并分片并保存文件信息
     */
    @PostMapping("/merge")
    public ResponseEntity<Map<String, Object>> mergeChunks(
            @RequestParam String fileMd5,
            @RequestParam String fileName,
            @RequestParam String fileType,
            @RequestParam Long fileSize,
            @RequestParam(defaultValue = "文件描述") String fileDescription,
            @RequestParam Integer categoryId) {

        Map<String, Object> result = new HashMap<>();

        try {
            FileInfo fileInfo = fileUploadUtil.mergeChunks(fileMd5, fileName, fileDescription, fileType, fileSize, categoryId);
            boolean success = fileInfoService.addFile(fileInfo);

            if (success) {
                result.put("success", true);
                result.put("message", "文件上传成功");
                result.put("fileInfo", fileInfo);
            } else {
                result.put("success", false);
                result.put("message", "文件信息保存失败");
            }
        } catch (IOException e) {
            result.put("success", false);
            result.put("message", "文件合并失败: " + e.getMessage());
        }

        return ResponseEntity.ok(result);
    }

    @GetMapping("/download")
    public ResponseEntity<Resource> downloadFile(@RequestParam("fileId") Integer fileId) {
        try {
            // 获取文件信息
            FileInfo fileInfo = fileInfoService.getFileById(fileId);
            if (fileInfo == null) {
                return ResponseEntity.notFound().build();
            }

            // 构建文件路径
            Path filePath = Paths.get(fileInfo.getFilePath()).normalize();


            Resource resource = new UrlResource(filePath.toUri());

            // 检查文件是否存在且可读
            if (!resource.exists() || !resource.isReadable()) {
                return ResponseEntity.notFound().build();
            }

            // 根据文件后缀获取正确的MIME类型
            String fileExtension = fileInfo.getFileType();
            String contentType = determineContentType(fileExtension);

            // 增加下载次数
            fileInfoService.incrementDownloadCount(fileId);

            // 构建响应
            return ResponseEntity.ok()
                    .contentType(MediaType.parseMediaType(contentType))
                    .header(HttpHeaders.CONTENT_DISPOSITION,
                            "attachment; filename=\"" + URLEncoder.encode(fileInfo.getOriginalName(), StandardCharsets.UTF_8.name()) + "\"")
                    .body(resource);
        } catch (MalformedURLException e) {
            // URL格式错误
            return ResponseEntity.badRequest().build();
        } catch (IOException e) {
            // 文件操作错误
            return ResponseEntity.internalServerError().build();
        } catch (Exception e) {
            // 其他未知错误
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    /**
     * 根据文件后缀确定MIME类型
     */
    private String determineContentType(String fileExtension) {
        if (fileExtension == null || fileExtension.isEmpty()) {
            return "application/octet-stream";
        }

        // 转换为小写并移除可能的点号
        String extension = fileExtension.toLowerCase().replace(".", "");

        // 常见文件类型映射
        switch (extension) {
            case "exe":
                return "application/x-msdownload";
            case "msi":
                return "application/x-msiinstaller";
            case "png":
                return "image/png";
            case "jpg":
            case "jpeg":
                return "image/jpeg";
            case "gif":
                return "image/gif";
            case "pdf":
                return "application/pdf";
            case "doc":
                return "application/msword";
            case "docx":
                return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            case "xls":
                return "application/vnd.ms-excel";
            case "xlsx":
                return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            case "ppt":
                return "application/vnd.ms-powerpoint";
            case "pptx":
                return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
            case "zip":
                return "application/zip";
            case "rar":
                return "application/x-rar-compressed";
            case "txt":
                return "text/plain";
            case "html":
                return "text/html";
            case "css":
                return "text/css";
            case "js":
                return "application/javascript";
            default:
                return "application/octet-stream";
        }
    }
}